import os

from sc_engine.apps import messages as msgs

from sc_engine.apps.data import NamedAliasedData
from sc_engine.repositories import Repository, use
from sc_engine.repositories.stores import PickleFileStore

class MapData(NamedAliasedData):
    """Houses the data for a map."""
    def __init__(self, name, version, width, height, aliases = None):
        self.version = version
        self.width = width
        self.height = height

        super(MapData, self).__init__(name, aliases)

def make_app(app_name, root_config, config):
    data_directory = root_config['data_directory']
    store_filename = os.path.join(data_directory, app_name)
    store = PickleFileStore(store_filename)
    repo = Repository(store)

    app = MapDataApp(repo)

    return {
        msgs.MapDataRequested : app.map_data_requested,
        msgs.MapFetchNonExistantMap : app.map_fetch_non_existant_map,
        msgs.MapFetchAnnouncement: app.map_fetch_announcement,
        msgs.MapNameDetermination: app.map_name_determination,
    }

class MapDataApp(object):
    """Control the local storing and distribution of info on maps.

    Will send out info for a map when requested, or when the details change. If
    info for a map is requested but no data is known for it, will send out a
    request to fetch it from the kespa web site.
    """
    def __init__(self, repo):
        self.repo = repo

    def _announce(self, maps, id):
        m = maps.get(id, None)

        if m is None:
            return msgs.MapDoesNotExistAnnouncement(id)
        else:
            return msgs.MapDataAnnouncement(id, m.name, m.version, m.width, m.height)

    @use('repo', 'maps')
    def map_data_requested(self, msg, maps):
        if msg.map_id not in maps:
            return msgs.MapFetchRequested(msg.map_id)

        return self._announce(maps, msg.map_id)

    @use('repo', 'maps')
    def map_fetch_non_existant_map(self, msg, maps):
        maps[msg.map_id] = None
        return self._announce(maps, msg.map_id)

    @use('repo', 'maps')
    def map_fetch_announcement(self, msg, maps):
        m = MapData(msg.name, msg.version, msg.width, msg.height)
        maps[msg.map_id] = m
        return self._announce(maps, msg.map_id)

    @use('repo', 'maps')
    def map_name_determination(self, msg, maps):
        alter_func = lambda p: p.determine_name(msg.true_name)
        maps[msg.map_id].determine_name(msg.true_name)
        return self._announce(maps, msg.map_id)


